Los base de datos usada fue extraída de: https://www.kaggle.com/lava18/google-play-store-apps#license.txt
# Librerías bases
import numpy as np
import pandas as pd
import scipy
# Para visualizar
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns
# Para ML
#separar data entrenamiento y prueba
from sklearn.model_selection import train_test_split
#árbol de decisión
from sklearn import tree
#Random Forest
from sklearn.ensemble import RandomForestClassifier
from sklearn.datasets import make_classification
#Revisar ML
from sklearn.metrics import confusion_matrix
from sklearn.metrics import accuracy_score
from sklearn.metrics import auc
from sklearn.tree import export_graphviz
from subprocess import call
from os import path
from PIL import Image
pip install wordcloud
df=pd.read_csv('./googleplaystore.csv')
df.head(5)
rowsiniciales=df.shape[0]
rowsiniciales #10841
#df=df.dropna()
#rowsfinales=df.shape[0]
#rowsfinales
b=df.nunique()
b
Notemos que hay APP que están repetidas. Acá se pueden hacer dos cosas:
df[df.isnull().any(axis=1)].count()
Varios columnas vacias
a=df.dtypes
a
Notemos que solo Ratings está en formato número y nos gustaría que install, price, reviews y size también lo estuvieran (para realizar gráficos es fundamental).
df.drop_duplicates(subset='App', inplace=True)
df.nunique()
df.shape[0]
Note Que ahora tenemos el mismo número de filas que de App distintas!
df['Installs']=df.Installs.apply(lambda x: x.replace('+','') if '+' in str(x) else x)
#df.head(5) #notemos que esto está bien (quitamos el +) ahora transformemoslo a número!
#df['Installs']=df.Installs.apply(lambda x: int(x)) #notemos que arroja error porque hay comas!!!!! (hay que eliminarlas)
df['Installs']=df.Installs.apply(lambda x: x.replace(',','') if ',' in str(x) else x)
#df['Installs']=df.Installs.apply(lambda x: int(x)) #arroga otro error porque dentro de las bases hay elementos que dicen Free
df=df[df['Installs']!='Free']
df['Installs']=df.Installs.apply(lambda x: int(x))
df.head(4)
#df.dtypes #Install está listo
mismo ahora con price
#df['Price']=df.Price.apply(lambda x: float(x)) #molestan los $
df['Price']=df.Price.apply(lambda x: x.replace('$','') if '$' in str(x) else x)
df['Price']=df.Price.apply(lambda x: float(x)) #listo!
df['Reviews']=df.Reviews.apply(lambda x: int(x)) #listo!
df['Size']=df.Size.apply(lambda x: x.replace('M','') if 'M' in str(x) else x)
#df['Size']=df.Size.apply(lambda x: float(x)) #problema con 'Varies with device'
#como argumento ( ojo puede ser útil está variable) se puede ver si se correlaciona positivamente con el ratings
#esto es porque intuitivamente si da libertad de peso de acuerdo al dispositivo deberìa funcionar mejor en todo tipo de dispositivo
#esto es solo una teoría
df[df['Size']=='Varies with device'].Rating.mean()
df[df['Size']!='Varies with device'].Rating.mean()
Notemos que la intuición era correcta!, sin embargo la diferenca es muy poca y sacaremos los valores que tengan 'Varies with device' para trabajar con está variable como número.
df['Size']=df.Size.apply(lambda x: x.replace('Varies with device','NaN') if 'Varies with device' in str(x) else x)
#df['Size']=df.Size.apply(lambda x: float(x)) notemos que hay aplicaciones que pesan kilobytes
df['Size'] = df.Size.apply(lambda x: float(x.replace('k', '')) / 1000 if 'k' in str(x) else x)
del df['Current Ver'] #la versión del aplicativo (se sacará está variable)
df.head(4)
df[df.isnull().any(axis=1)].count()
df=df.dropna()
df.nunique()
df['Size'] = df.Size.apply(lambda x: float(x))
df.dtypes
df[df.isnull().any(axis=1)].count()
df=df.dropna()
df.nunique()
df[df.isnull().any(axis=1)].count()
Hipotesis (revisar si la intuición es correcta) [Lluvia de ideas]
Considerar cada categoria como una industria en el sentido que cada una tiene su rentabilidad y una variación de rentabilidad (recordar: https://aprendeingenieria.com/evidencia-cientifica-estrategia-rentabilidad/). La rentabilidad puede ser una función del Rating y del número de Install. (por ejemplo se multiplican ambas variables. Si está el rating en el promedio se normaliza a 1). Todas las App deben ganar de alguna forma ya sea por publicidad o por que son pagadas.
Analizar información en base a las cosas que se deciden y las que son un resultado.
Ideas interesante 1:
Idea interesante 2: Antes de meterse a hacer una APP en una categoria conviene saber, cuales son las APP más populares de ella y las más comentadas por sus usuarios. La primera variable es simplemente la APP con más Install en cada categoria. La segunda variable es el ratio entre reviews/Install. Se calcula para cada APP. Las APP con está metrica más altas son las APP más "polémicas". Ya que tienen una taza alta de que al ser descargada su usuario haga un review. aca solo se trabajará con más review y ellas serán consideradas las aplicaciones tipo de la categoria.
df.describe() #la mediana del rating es 4.3
number_of_apps_in_Category_free = df[df['Type']=='Free'].Category.value_counts().sort_values(ascending=False)
number_of_apps_in_Category_free=number_of_apps_in_Category_free.to_frame()
number_of_apps_in_Category_free.columns=['Num_APP_free']
number_of_apps_in_Category_paid = df[df['Type']=='Paid'].Category.value_counts().sort_values(ascending=False)
number_of_apps_in_Category_paid=number_of_apps_in_Category_paid.to_frame()
number_of_apps_in_Category_paid.columns=['Num_APP_paid']
#competence = number_of_apps_in_Category_paid.merge(number_of_apps_in_Category_free, on='Category', how='right')
#number_of_apps_in_Category_free
paid_vs_free= number_of_apps_in_Category_free.merge(number_of_apps_in_Category_paid, how='outer', left_index=True, right_index=True)
#free_vs_paid
paid_vs_free=paid_vs_free.fillna(0)
#paid_vs_free
paid_vs_free=paid_vs_free.assign(paid_vs_free= lambda x: (x.Num_APP_paid)/(x.Num_APP_free))
paid_vs_free.sort_values(by=['paid_vs_free'], ascending=False)
Mostrar en sitio está tabla: Esta tabla está ordenada dada la proporción entre aplicaciones pagadas y gratuitas por categorías. Pese, a que si la aplicación es pagada o no depende del modelo de negocio de la compañia, es importante que antes de decidir esto conozca su mercado. Si usted desea crear una aplicación revise está tabla y vea como se comportan las otras aplicaciones dentro de está categoría. (https://aprendeingenieria.com/modelos-de-negocio-y-estrategia/)
df.columns
Rating_promedio=df[['Category','Rating']].groupby('Category').mean()
Rating_promedio=Rating_promedio.sort_values(by=['Rating'], ascending=False)
Rating_promedio.columns=['Rating_promedio']
Rating_promedio
mas_reviews=df.sort_values(by=['Reviews'], ascending=False) #df.drop_duplicates(subset='App', inplace=True)
mas_reviews.drop_duplicates(subset='Category', keep='first',inplace=True)
mas_reviews #Aplicaciones con más comentarios
Estas son aplicaciones relativamente dominantes por categorias. tienen la mejor nota y son conocidas.
mejor_rating=df[df['Reviews']>=10000].sort_values(by=['Rating'], ascending=False) # considerar solo aplicaciones con varios reviews
mejor_rating.drop_duplicates(subset='Category', keep='first',inplace=True)
mejor_rating
Note que está tabla es interesante ya que dice que en la categoria de eventos la mejor aplicación tiene 4,4 (mala nota). Notese que se tiene la restricción de sobre los 10.000 reviews (esto para tener una nota validada por varios usuarios). Es decir, puede ser interesante incursionar con una aplicación en esta categoria.
df_review=df[df['Reviews']>=1000]
Rating_promedio2=df_review[['Category','Rating']].groupby('Category').mean()
Rating_promedio2=Rating_promedio2.sort_values(by=['Rating'], ascending=False)
Rating_promedio2.columns=['Rating_promedio']
Rating_promedio2
Será esta diferencia estadísticamente significativa?
df_short=df[df['Reviews']>=100]
df_fix=df_short.copy()
#df_short
#ESTO ES DEBIDO A QUE SON MUY POCOS APP CON ESTÁS CARACTERÍSTICAS
df_fix=df_fix[df_fix['Content Rating'] != 'Adults only 18+']
df_fix=df_fix[df_fix['Content Rating'] != 'Unrated']
df_fix['installs']=df_fix['Installs'].apply(lambda x: np.log(x))
df_fix['reviews']=df_fix['Reviews'].apply(lambda x: np.log(x))
number_of_apps_in_category = df_short['Category'].value_counts().sort_values(ascending=False)
df_short.columns
number_of_apps_in_category
number_of_apps_in_category = df_fix['Category'].value_counts()
number_of_apps_in_category
labels = number_of_apps_in_category.index
values = number_of_apps_in_category.values
fig1, ax1 = plt.subplots(figsize=(10, 15))
ax1.pie(values, labels=labels, autopct='%1.1f%%',
shadow=True, startangle=90)
ax1.axis('equal')
plt.title("Distribución Categorías", size = 20)
plt.show()
number_of_apps_for_type = df_fix['Type'].value_counts()
number_of_apps_for_type
labels = number_of_apps_for_type.index
values = number_of_apps_for_type.values
fig1, ax1 = plt.subplots(figsize=(10, 15))
ax1.pie(values, labels=labels, autopct='%1.1f%%',
shadow=True, startangle=90)
ax1.axis('equal')
plt.title("Distribución de APP pagadas y gratuitas", size = 20)
plt.show()
g=sns.pairplot(df_fix,vars=['Rating', 'reviews', 'Size', 'installs'], hue='Type')
Análisis:
Se ha marcado en negrita los resultados no triviales de estos gráficos.
Viendo solo la diagonal de este gráfico se observa que:
Las aplicaciones pagadas tienen mucho menos instalaciones y reviews (A ambos atributos se le aplico logaritmo). Pero mejor Rating.
Al mirar a los gráficos no presentes en las diagonales.
Las aplicaciones pagadas tienen un review bastante alto dado sus instalaciones.
En general las aplicaciones con mejor nota tiene más descarga.
En la distribución de tamaño en MB las pagadas y gratis distribuyen relativamente igual.
number_of_apps_in_content_rating = df_fix['Content Rating'].value_counts()
number_of_apps_in_content_rating
labels = number_of_apps_in_content_rating.index
values = number_of_apps_in_content_rating.values
fig1, ax1 = plt.subplots(figsize=(10, 15))
ax1.pie(values, autopct='%1.1f%%',
startangle=90)
ax1.axis('equal')
plt.title("Distribución del Content Rating", size = 20)
ax1.legend(labels,
title="Content Rating",
loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
plt.show()
a=sns.pairplot(df_fix,vars=['Rating', 'reviews', 'Size', 'installs'], hue='Content Rating')
(Dado los pocos datos de Adults only 18+ y Unrated no se considerarán en el análisis.) (note que los colores se inviertieron en mature 17+ y everyone 10+) De la diagonal del gráfico se observa que: las APP "para todos los sobre 10" años son las que distribuyen de forma más diferente al resto. Tienen más rating y más review para una misma cantidad de install que las App de otros contenidos. Por otra parte categorías para everyone son las que tienen menos review para la misma cantidad de install y son las App más livianas.
Al analizar la categoría everyone 10+ se observa que está altamente cargada a los juegos.
number_of_apps_in_category = df_fix['Category'].value_counts().sort_values(ascending=False)
#number_of_apps_in_category
number_of_apps_in_category = df[df['Content Rating']=='Everyone 10+'].Category.value_counts().sort_values(ascending=False)
#number_of_apps_in_category
Las App de content rating igual a everyone 10+ son principalmente juegos por ende es "esperable que pesen más MB" que el resto.
number_of_apps_in_category = df[df['Content Rating']=='Everyone'].Category.value_counts().sort_values(ascending=False)
#number_of_apps_in_category
df_fix1=df_fix[df_fix['Price']!=0]
p = sns.stripplot(x="Price", y="Content Rating", data=df_fix1, jitter=True, linewidth=1)
p = sns.stripplot(x="Price", y="Content Rating", data=df_fix1[df_fix1['Price']<100], jitter=True, linewidth=1)
Pese a que everyone 10+ y mature 17+ tienen casi la misma cantidad de Apps, Everyone 10+ posee mucha más Apps pagadas.
fig, ax = plt.subplots()
fig.set_size_inches(15, 8)
p = sns.stripplot(x="Price", y="Category", data=df_fix1[df_fix1['Price']<100], jitter=True, linewidth=1)
Ahora que sabe esta distribución por precio, ¿Cuál es el mejor precio para su App?
fig, ax = plt.subplots()
fig.set_size_inches(15, 8)
p = sns.stripplot(x="Size", y="Category", data=df_fix1, jitter=True, linewidth=1)
import scipy.stats as stats
anova = stats.f_oneway(df_fix.loc[df.Category == 'TOOLS']['Rating'],
df_fix.loc[df.Category == 'FAMILY']['Rating'],
df_fix.loc[df.Category == 'GAME']['Rating'],
)
print(anova)
kruskal=stats.kruskal(df_fix.loc[df.Category == 'TOOLS']['Rating'],
df_fix.loc[df.Category == 'FAMILY']['Rating'],
df_fix.loc[df.Category == 'GAME']['Rating'],
)
print(kruskal)
df_fix.describe()
df_fix['rating']=0
df_fix['rating']=(df_fix['Rating']>=4.6)*1
df_fix.rating.value_counts()
y=df_fix['rating'].copy()
category=pd.get_dummies(df_fix.Category)
genres=pd.get_dummies(df_fix.Genres)
content_rating=pd.get_dummies(df_fix['Content Rating'])
obj=[df_fix,category,content_rating]
df_fix=pd.concat(obj,axis=1)
df_fix.head(3)
df_fix.columns
number_of_apps_in_category
features=['Size','Price','FAMILY', 'TOOLS','GAME', 'Everyone',
'Everyone 10+', 'Mature 17+', 'Teen']
X=df_fix[features].copy()
#X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.33, random_state=324)
La idea no es predecir, sino que entender cuales son las mejores Apps dado ciertos atributos. Se usa un árbol de decisión para separar las mejores aplicaciones de las peores reduciendo la heterogeneidad de los grupos.
rating_classifier = tree.DecisionTreeClassifier(max_leaf_nodes=15, random_state=0,min_samples_leaf=8)
rating_classifier.fit(X, y)
tree.export_graphviz(rating_classifier)
export_graphviz(rating_classifier, 'tree2.dot', rounded = True,
feature_names = ['Size','Price','FAMILY', 'TOOLS','GAME', 'Everyone',
'Everyone 10+', 'Mature 17+', 'Teen'],
class_names = ['regulares', 'buenisimos'], filled = True)
call(['dot', '-Tpng', 'tree2.dot', '-o', 'tree2.png', '-Gdpi=400']);
from IPython.display import Image
Image('tree2.png')
Siguiendo el árbol las mejores aplicaciones están en: precio menor a 1.345 dólares pesan entre 61 y 63 MB y son para Teen
rating_classifier = tree.DecisionTreeClassifier(max_leaf_nodes=20, random_state=0,min_samples_leaf=5)
rating_classifier.fit(X, y)
tree.export_graphviz(rating_classifier)
export_graphviz(rating_classifier, 'tree2.dot', rounded = True,
feature_names = ['Size','Price','FAMILY', 'TOOLS','GAME', 'Everyone',
'Everyone 10+', 'Mature 17+', 'Teen'],
class_names = ['regulares', 'buenisimos'], filled = True)
call(['dot', '-Tpng', 'tree2.dot', '-o', 'tree2.png', '-Gdpi=400']);
from IPython.display import Image
Image('tree2.png')
df_fix.columns
df_fix[df_fix['Content Rating']=='Teen'].Category.value_counts()
falta probar clustering! y ver si jugar con reviews,rating, sizing, price. Luego al tener los clustering ver en que categorìa caen ciertos cluster o géneros
from sklearn.preprocessing import StandardScaler
from sklearn.cluster import KMeans
from itertools import cycle, islice
import matplotlib.pyplot as plt
from pandas.plotting import parallel_coordinates
Labels2=['Rating', 'Reviews', 'Size', 'Installs','Price']
X2=df_fix[Labels2].copy()
X2=StandardScaler().fit_transform(X2)
def distancia_centroid(X2, i):
kmeans = KMeans(n_clusters=i)
model = kmeans.fit(X2)
distance=model.inertia_
return distance
Distancias=[]
n_clusters=[]
for i in range(1,30):
distancia=distancia_centroid(X2, i)
Distancias.append(distancia)
n_clusters.append(i)
loss1=pd.DataFrame(data=n_clusters, columns= ['n_clusters'])
loss2=pd.DataFrame(data=Distancias, columns= ['distancia'])
obj=[loss1,loss2]
loss=pd.concat(obj, axis=1)
loss
b = sns.catplot(x="n_clusters", y="distancia",
data=loss, kind="point",
height=5, aspect=1.5);
Hay 4 o 5 clusters en el segmento de las aplicaciones
kmeans = KMeans(n_clusters=5, n_init=15,max_iter=1000)
model = kmeans.fit(X2)
print("model\n", model)
centers = model.cluster_centers_
model.inertia_
def pd_centers(featuresUsed, centers):
colNames = list(featuresUsed)
colNames.append('prediction')
# Zip with a column called 'prediction' (index)
Z = [np.append(A, index) for index, A in enumerate(centers)]
# Convert to pandas data frame for plotting
P = pd.DataFrame(Z, columns=colNames)
P['prediction'] = P['prediction'].astype(int)
return P
def parallel_plot(data):
my_colors = list(islice(cycle(['b', 'y', 'g', 'r', 'k']), None, len(data)))
plt.figure(figsize=(15,8)).gca().axes.set_ylim([-3,+15])
parallel_coordinates(data, 'prediction', color = my_colors, marker='o')
P = pd_centers(Labels2, centers)
P
parallel_plot(P)
df_fix['clusters']=model.labels_
df_fix[df_fix['clusters']==2] #conoce estás App?? probablemente sí!
df_fix.clusters.value_counts()
fig, ax = plt.subplots()
fig.set_size_inches(15, 8)
p = sns.stripplot(x="clusters", y="Rating", data=df_fix, jitter=True, linewidth=1)
fig, ax = plt.subplots()
fig.set_size_inches(15, 8)
p = sns.stripplot(x="clusters", y="Price", data=df_fix, jitter=True, linewidth=1)
a=sns.pairplot(df_fix,vars=['Rating', 'reviews', 'Size', 'installs'], hue='clusters')
todas las app pesan distinto pero los gráficos muestran en general una idea que las app de juegos pesan más que el resto es esto cierto?
df_fix[df_fix['Category']=='GAME'].Size.describe()
df_fix[df_fix['Category']!='GAME'].Size.describe()
df_fix.columns
b=df_fix.dtypes
df_fix[df_fix['clusters']==0].Category.value_counts()
df_fix[df_fix['clusters']==1].Category.value_counts()
df_fix[df_fix['clusters']==2].Category.value_counts()
df_fix[df_fix['clusters']==3].Category.value_counts()
df_fix[df_fix['clusters']==4].Category.value_counts()
df1=pd.read_csv('./googleplaystore_user_reviews.csv')
df1.head()
df=pd.merge(df1,df_fix, on="App", how="inner")
df.head(4)
grouped_sentiment_app_count = df.groupby(['App', 'Rating','reviews','Type','installs','Size']).agg({'Sentiment_Polarity': 'mean','Sentiment_Subjectivity': 'mean'}).reset_index()
grouped_sentiment_app_count.sort_values(by=['Rating','Sentiment_Subjectivity','Rating'], ascending=False)
corr = grouped_sentiment_app_count.corr()
ax = sns.heatmap(
corr,
vmin=-1, vmax=1, center=0,
cmap=sns.diverging_palette(10, 200, n=200),
square=True
)
ax.set_xticklabels(
ax.get_xticklabels(),
rotation=45,
horizontalalignment='right'
);
a=sns.pairplot(grouped_sentiment_app_count,vars=['Rating', 'Sentiment_Polarity', 'Sentiment_Subjectivity', 'reviews','installs','Size'], hue='Type')
#grouped_sentiment_category_sum = df.groupby(['Category']).agg({'Sentiment': 'count'}).reset_index()
#grouped_sentiment_category_sum
#df_sentiment=pd.merge(grouped_sentiment_category_sum,grouped_sentiment_category_count, how='inner', on='Category')
#df_sentiment
grouped_sentiment_category_count = df.groupby(['Category', 'Sentiment']).agg({'App': 'count'}).reset_index()
grouped_sentiment_category_count.head(5)
df1=pd.DataFrame()
df2=pd.DataFrame()
df3=pd.DataFrame()
df1['Category']=grouped_sentiment_category_count[grouped_sentiment_category_count['Sentiment']=='Negative'].Category
df2['Category']=grouped_sentiment_category_count[grouped_sentiment_category_count['Sentiment']=='Positive'].Category
df3['Category']=grouped_sentiment_category_count[grouped_sentiment_category_count['Sentiment']=='Neutral'].Category
df2.head()
df1['Negative']=grouped_sentiment_category_count[grouped_sentiment_category_count['Sentiment']=='Negative'].App
df2['Positive']=grouped_sentiment_category_count[grouped_sentiment_category_count['Sentiment']=='Positive'].App
df3['Neutral']=grouped_sentiment_category_count[grouped_sentiment_category_count['Sentiment']=='Neutral'].App
df4=pd.merge(df1,df2, how='inner', on='Category')
df5=pd.merge(df3,df4, how='inner', on='Category')
df5['Total']=df5['Neutral']+df5['Negative']+df5['Positive']
df5['positive']=df5['Positive']/df5['Total']
df5['neutral']=df5['Neutral']/df5['Total']
df5['negative']=df5['Negative']/df5['Total']
df5['total']=1
df5=df5.sort_values(by=['positive','neutral'])
df5.head(2)
df5.tail(2)
df6=df5.sort_values(by=['negative'], ascending=False)
df6.head(2)
df7=df5.sort_values(by=['neutral'], ascending=False)
df7
BEAUTY es la categoría que tiene menor proporción de comentarios escritos positivos. Es decir, la menos amada por sus usuarios. Además tiene muchos comentarios neutrales, es decir no evoca fuertes sentimientos sus aplicaciones. GAME, por otra parte, es la categoría con más aplicaciones odiadas. Es una categoría con muy pocos mensajes neutrales. Las aplicaciones son amadas o odiadas al parecer no hay punto intermedio. las categorías AUTO_AND_VEHICLES y HEALTH_AND_FITNESS son las más amadas.
sizes=[0.536424,0.274834,0.188742]
fig1, ax1 = plt.subplots(figsize=(10, 15))
ax1.pie(sizes, autopct='%1.1f%%',
startangle=90)
plt.title("Distribución de tipos de comentarios de la categoría BEAUTY", size = 20)
ax1.legend(['positivo','neutral','negativo'],
title="Tipo de comentario",
loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
plt.show()
sizes=[0.589779,0.043746, 0.366474]
fig1, ax1 = plt.subplots(figsize=(10, 15))
ax1.pie(sizes, autopct='%1.1f%%',
startangle=90)
plt.title("Distribución de tipos de comentarios de la categoría GAME", size = 20)
ax1.legend(['positivo','neutral','negativo'],
title="Tipo de comentario",
loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
plt.show()
sizes=[0.810976,0.121951,0.067073]
fig1, ax1 = plt.subplots(figsize=(10, 15))
ax1.pie(sizes, autopct='%1.1f%%',
startangle=90)
plt.title("Distribución de tipos de comentarios de la categoría AUTO_AND_VEHICLES", size = 20)
ax1.legend(['positivo','neutral','negativo'],
title="Tipo de comentario",
loc="center left",
bbox_to_anchor=(1, 0, 0.5, 1))
plt.show()
df.head(2)
from wordcloud import WordCloud
wc = WordCloud(background_color="white", max_words=200, colormap="Set2")
from nltk.corpus import stopwords
stop = stopwords.words('english')
stop = stop + ['app', 'APP' ,'ap', 'App', 'apps', 'application', 'browser', 'website', 'websites', 'chrome', 'click', 'web', 'ip', 'address',
'files', 'android', 'browse', 'service', 'use', 'one', 'download', 'email', 'Launcher']
df['Translated_Review'] = df['Translated_Review'].apply(lambda x: " ".join(x for x in str(x).split(' ') if x not in stop))
df.dropna(subset=['Translated_Review'], inplace=True)
good = df.loc[df.Rating>4.5]['Translated_Review'].apply(lambda x: '' if x=='nan' else x)
wc.generate(''.join(str(good)))
plt.figure(figsize=(10, 10))
plt.figure()
plt.imshow(wc, interpolation="bilinear")
plt.axis("off")
plt.show()
from nltk.corpus import stopwords
stop = stopwords.words('english')
stop = stop + ['app', 'APP' ,'ap', 'App', 'apps', 'application', 'browser', 'website', 'websites', 'chrome', 'click', 'web', 'ip', 'address',
'files', 'android', 'browse', 'service', 'use', 'one', 'download', 'email', 'Launcher']
df['Translated_Review'] = df['Translated_Review'].apply(lambda x: " ".join(x for x in str(x).split(' ') if x not in stop))
df.dropna(subset=['Translated_Review'], inplace=True)
bad = df.loc[df.Rating<4.0]['Translated_Review'].apply(lambda x: '' if x=='nan' else x)
wc.generate(''.join(str(bad)))
plt.figure(figsize=(70, 70))
plt.figure()
plt.imshow(wc, interpolation="bilinear")
plt.axis("off")
plt.show()
Construí y trabajé con ayuda a este gran Kernel: https://www.kaggle.com/lava18/all-that-you-need-to-know-about-the-android-market